package com.cavy.platform.server.domain;

import com.cavy.platform.server.domain.job.GitRemoteJob;
import com.cavy.platform.server.domain.job.Job;
import com.cavy.platform.server.domain.job.PendingJob;
import com.cavy.platform.server.util.UuidUtil;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @author 唐旭
 * @Date 2018/7/20
 */
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class GitRemotePipeline extends Pipeline {
    public static final String DEFAULT_BRANCH = "master";
    public static final String ENV_NAME = "java.io.tmpdir";
    private String url;
    private String branch = DEFAULT_BRANCH;
    private String username;
    private String password;
    private String filePath;

    public GitRemotePipeline() {
    }

    public GitRemotePipeline(String name, String projectName, String workspace) {
        this.name = name;
        this.project = new Project().setName(projectName).setWorkSpace(new WorkSpace().setName(workspace));
    }

    @Override
    public void addStage(Stage stage) {
        throw new UnsupportedOperationException("git流水线不支持此操作");
    }

    @Override
    public void removeStage(String name) {
        throw new UnsupportedOperationException("git流水线不支持此操作");
    }

    @Override
    public Stage findStage(String stageName) {
        //TODO:后续考虑支持
        throw new UnsupportedOperationException("git流水线不支持此操作");
    }

    @Override
    public Pipeline setStageList(List<Stage> stageList) {
        return super.setStageList(stageList);
    }

    @Override
    @JsonIgnore
    public List<Stage> getStageList() {
        readPipeline();
        return super.getStageList();
    }

    @Override
    //目录如何组织?
    public PendingJob jobBuild(JobConfig jobConfig) {
        readPipeline();
        PendingJob pendingJob = super.jobBuild(jobConfig);
        GitRemoteJob job = (GitRemoteJob) pendingJob.getJob();
        job.setBranch(branch).setFilePath(filePath).setUrl(url);
        return pendingJob;
    }

    @Override
    protected Job getJobInstance() {
        return new GitRemoteJob();
    }

    private void readPipeline() {
        String property = System.getProperty(ENV_NAME);
        property = property + File.separator + "cavy-" + UuidUtil.generateShortUuid();
        File directory = new File(property);
        try {
            String hash = getRefHash();
            cloneRepositoryFile(hash, directory);
        } catch (GitAPIException e) {
            throw new RuntimeException(e);
        }
        //将文件内容读取为流水线
        readStageList(directory);
        //TODO:是否要删除这个临时目录呢?
//        FileUtils.delFolder(directory.getPath());
    }

    private void readStageList(File directory) {
        File f = new File(directory, filePath);
        ObjectMapper mapper = new ObjectMapper();
        try {
            JavaType javaType = mapper.getTypeFactory().constructParametricType(ArrayList.class, Stage.class);
            List<Stage> stages = mapper.readValue(f, javaType);
            this.stageList.addAll(stages);
        } catch (JsonParseException | JsonMappingException e) {
            throw new RuntimeException("流水线文件解析错误,请检查流水线文件定义");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void cloneRepositoryFile(String hash, File directory) throws GitAPIException {
        CloneCommand cloneCommand = Git.cloneRepository()
                .setURI(url)
                .setBranch(branch)
                .setDirectory(directory)
                .setNoCheckout(true);
        //账号密码如果为空,那么不设置
        if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) {
            cloneCommand.setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password));
        }
        Git call = cloneCommand.call();
        call.checkout()
                .setStartPoint(hash)
                .addPath(filePath).call();
        call.getRepository().close();
    }

    private String getRefHash() throws GitAPIException {
        Collection<Ref> call = Git.lsRemoteRepository().setRemote(url).call();
        for (Ref ref : call) {
            String[] split = ref.getName().split("/");
            String s = split[split.length - 1];
            if (branch.equalsIgnoreCase(s)) {
                return ref.getObjectId().getName();
            }
        }
        throw new RuntimeException("未找到分支:" + branch);
    }
}
